/**
 * 结合dot.js模板 构建的下拉选择框
 * 使用：app = $.fn.Select()
 * app.setData() 设置data数组
 * app.getValue() 获取当前选择的值(已经做了： update)
 * app.update() 更新
 * version : 1.1.3
 * 选择事件触发顺序 ： select > show
 * log : 20170804 新增 触发按钮(sn-selectBtn) 可以添加 class、id 属性, 添加input  change事件
 * log : 20170825 新增 show 事件 监听 列表展示状态 show(state, s-id); 并且 移除(20170804中) input  change事件
 * log : 20170907 解决(bug) update() 时候 默认值 为空没有重置input的value值。
 */
;
(function($, window, document, undefined) {
    var SELECT = function($this, option) {
        this._o = {};
        this.o = $.extend({
            //可设置设置属性
            width: 200, //容器的宽度
            height: 32, //容器的高度
            maxCount: 10, //下拉最大显示条数
            optionHeight: 40, //下拉option的高度
            inputClassName: "", //设置保存值input的class属性  注意：这里只保存 值
            inputName: "", //设置保存值input的 name属性
            inputIdName: "", //设置保存值input的id属  注意 : 如果设置了该项 绑定的对象请唯一
            selectBarClassName : "", //设置 select按钮 class属性
            selectBarIdName : "", //设置 select按钮 id属性
            defaultIndex: -1, //初始化默认值索引 注意：-1 表示空  placeholder
            placeholder: "", //设置 当(defaultIndex = -1)的时候 select的提示信息
            listTemplate: "", //option 模板选择器
            select: function(currentValue, index, id) {}, //选择事件
            show : function(state , id){}, // 下拉列表展示、隐藏事件
            source: "text", //text、html 区别在于选择的时候获取的列表 data-text属性值 ，还是列表中的html 作为显示结果
            data: [] //用于显示列表的数组
        }, option);
        this.d = { //用于保存不可修改的属性 注意：如若需要修改 则要修改对应样式表 否则会出现样式混乱
            //禁止设置属性
            selectBtn: "sn-selectBtn", //触发按钮类名
            selectBox: "sn-selectBox", //选择列表容器类名
            selectOption: "sn-selectOption", //选择列表类名
            mark: "s-id", //标识符号 用于查找
            id: Math.random()
                .toString(36)
                .slice(-6), //标识id 用于绑定查找、绑定事件
            _self: $this
        }
    }

    SELECT.prototype.init = function() {
        //1.初始化容器
        initContainer(this.o, this.d);
        //2.创建input 隐藏域
        this._o.i = createInput(this.o, this.d);
        //3.创建selectBtn按钮
        this._o.s = createSelectBtn(this.o, this.d);
        //4.创建下拉selectBox容器
        this._o.b = createSelectBox(this.o, this.d);
        //7.绑定展开事件
        onShowOption(this._o, this.d,this.o);
    }

    SELECT.prototype.update = function() {
        //5.渲染列表选项
        this._o.l = renderOption(this.o, this.d, this._o);
        //6.设置默认值
        setDefault(this.o, this._o);
        //6.绑定选择列表事件
        onSelectOption(this.o, this._o, this.d);
    }

    SELECT.prototype.setData = function(data) {
        this.o.data = data;
        this.update();
    }

    SELECT.prototype.getValue = function() {
        return this._o.i.val();
    }

    function initContainer(o, d) {
        d._self.css(getStyle(o, d))
            .attr(d.mark, d.id)
            .attr("tabIndex", "0");
    }

    function getStyle(o, d) {
        var r = {};
        r.width = parseInt(o.width);
        r.height = parseInt(o.height);
        r.outline = "none";
        if(['static', 'inherit', 'initial'].indexOf(d._self.css("position")) > -1) {
            r.position = "relative";
        }
        return r;
    }

    function createInput(o, d) {
        var e = document.createElement("input");
        e.setAttribute(d.mark, d.id);
        e.name = o.inputName;
        e.id = o.inputIdName;
        e.className = o.inputClassName;
        e.type = "hidden";
        d._self.append(e);
        return $(e);
    }

    function createSelectBtn(o, d) {
        var e = document.createElement("span");
        e.setAttribute(d.mark, d.id);
        e.className = d.selectBtn+" "+o.selectBarClassName;
        e.id = o.selectBarIdName;
        e.tabIndex = "";
        e.style.lineHeight = (parseInt(o.height) - 2) + "px";
        d._self.append(e);
        return $(e);
    }

    function createSelectBox(o, d) {
        var e = document.createElement("ul");
        e.setAttribute(d.mark, d.id);
        e.className = d.selectBox;
        e.style.position = "absolute";
        e.style.top = parseInt(o.height) + "px";
        e.style.maxHeight = parseInt(o.maxCount) * parseInt(o.optionHeight) + "px";
        d._self.append(e);
        return $(e);
    }

    function renderOption(o, d, _o) {
        var it = {
            mark: d.mark,
            id: d.id,
            className: d.selectOption,
            data: o.data
        }
        render(_o.b, $(o.listTemplate), it);
        var l = $('.' + d.selectOption + '[' + d.mark + "=" + d.id + ']');
        l.css("line-height", parseInt(o.optionHeight) + "px");
        return l;
    }

    function render($container, $tmp, data) {
        var tmpObj = doT.template($tmp.html())
        $container.html(tmpObj(data));
    }

    function setDefault(o, _o) {
        var index = parseInt(o.defaultIndex);
        if(0 <= index && index < o.data.length) {
            var $s = _o.l.eq(index);
            _o.i.val($s.attr("data-value"));
            if(o.source === 'html') {
                _o.s.html($s.html());
            } else {
                _o.s.text($s.attr("data-text"));
            }
            $s.addClass("selected")
                .siblings()
                .removeClass("selected");
        } else {
            _o.s.text(o.placeholder);
            _o.i.val('');
        }
    }

    function onShowOption(_o, d, o) {
        _o.s.click(function() {
            _o.b.toggleClass("active");
            if(_o.b.hasClass("active")) {
                d._self.focus();
                if(typeof o.show === 'function'){
                    o.show(true,d.id);
                }
            }
        })
        d._self.blur(function() {
            if(_o.b.hasClass("active")) {
                setTimeout(function() {
                    _o.b.removeClass("active");
                    if(typeof o.show === 'function'){
                        o.show(false,d.id);
                    }
                }, 200)
            }
        })
    }

    function onSelectOption(o, _o, d) {
        _o.l.click(function() {
            d._self.blur();
            if(o.source === 'text') {
                _o.s.text($(this)
                    .attr("data-text"));
            } else {
                _o.s.html($(this)
                    .html());
            }
            $(this)
                .addClass("selected")
                .siblings()
                .removeClass("selected");
            _o.i.val($(this)
                .attr("data-value"));
            _o.b.removeClass("active");
            if(typeof o.select === 'function') {
                o.select($(this)
                    .attr("data-value"), $(this)
                    .index(), d.id);
            }
        })
    }
    
    if(!Array.prototype.indexOf) {
        Array.prototype.indexOf = function(ele) {
            // 获取数组长度
            var len = this.length;
            // 检查值为数字的第二个参数是否存在，默认值为0
            var fromIndex = Number(arguments[1]) || 0;
            // 当第二个参数小于0时，为倒序查找，相当于查找索引值为该索引加上数组长度后的值
            if(fromIndex < 0) {
                fromIndex += len;
            }
            // 从fromIndex起循环数组
            while(fromIndex < len) {
                // 检查fromIndex是否存在且对应的数组元素是否等于ele
                if(fromIndex in this && this[fromIndex] === ele) {
                    return fromIndex;
                }
                fromIndex++;
            }
            // 当数组长度为0时返回不存在的信号：-1
            if(len === 0) {
                return -1;
            }
        }
    }

    $.fn.Select = function(option) {
        var a = new SELECT(this, option);
        a.init();
        a.update();
        return a;
    }
})(jQuery, window, document);
